#include <kernel.h>

/**
 * Attach to hardware interrupt
 *
 * \param irq          IRQ number to attach to
 * \param shared       set to 1 if interrupt sharing is supported; set to 0
 *                     otherwise
 * \param thread_init  called just after DDE kit internal init and before any
 *                     other function
 * \param handler      IRQ handler for interrupt irq
 * \param priv         private token (argument for thread_init and handler)
 *
 * \return             attachment state
 * \retval 0           success
 * \retval !0          error
 */

struct dk_irq_hook_s dk_irq_hooks[32];

static void
dk_intr_attach_thread_container(void *_)
{
	 struct dk_irq_hook_s *hook = (struct dk_irq_hook_s *)_;
	 hook->thread_init(hook->priv);

	 while (1)
	 {
		  semaphore_acquire(&hook->sem, NULL, NULL);
		  hook->handler(hook->priv);
		  ekf_intr_irq_eoi(hook - &dk_irq_hooks[0]);
	 }
}

static void
dk_irq_handler(int irq, int c)
{
	 while (-- c >= 0)
		  semaphore_release(&dk_irq_hooks[irq].sem);
}

int
LD_SYM(dde_kit_interrupt_attach)(int irq, int shared, void(*thread_init)(void *),
						  void(*handler)(void *), void *priv)
{
	 
	 dk_irq_hooks[irq].thread_init = thread_init;
	 dk_irq_hooks[irq].handler = handler;
	 dk_irq_hooks[irq].priv = priv;
	 dk_irq_hooks[irq].sc = dk_irq_hooks[irq].rc = 0;
	 semaphore_init(&dk_irq_hooks[irq].sem, 0);
	 proc_attach(dk_irq_hooks[irq].proc =
				 kthread_create("__dk_intr", 16, 0, (void(*)(void *))dk_intr_attach_thread_container, &dk_irq_hooks[irq], 0));
	 dk_irq_hooks[irq].attach = 1;
	 intr_irq_handler_set(irq, dk_irq_handler, 0);
	 ekf_intr_irq_line_enable(irq);
	 ekf_intr_irq_eoi(irq);
	 
	 ekf_kprintf("irq %d hooked\n", irq);
	 
	 return 0;
}

/**
 * Detach from a previously attached interrupt.
 *
 * \param irq          IRQ number
 */
void
LD_SYM(dde_kit_interrupt_detach)(int irq)
{
	 dk_irq_hooks[irq].attach = 0;
	 ekf_kprintf("NOT IMPLEMENTED\n");
}

/**
 * Block interrupt.
 *
 * \param irq          IRQ number to block
 */
void
LD_SYM(dde_kit_interrupt_disable)(int irq)
{
	 // pic_disable(irq);
	 ekf_kprintf("NOT IMPLEMENTED\n");
}

/**
 * Enable interrupt.
 *
 * \param irq          IRQ number to block
 */
void
LD_SYM(dde_kit_interrupt_enable)(int irq)
{
	 // pic_enable(irq);
	 ekf_kprintf("NOT IMPLEMENTED\n");
}

#if DK_EXPORT_SYM

void
LD_SYM(dde_kit_intr_symbol)(void)
{
	 elf_mod_export_symbol("dde_kit_interrupt_attach", &dde_kit_interrupt_attach, 1);
	 elf_mod_export_symbol("dde_kit_interrupt_detach", &dde_kit_interrupt_detach, 1);
	 elf_mod_export_symbol("dde_kit_interrupt_disable", &dde_kit_interrupt_disable, 1);
	 elf_mod_export_symbol("dde_kit_interrupt_enable", &dde_kit_interrupt_enable, 1);
}

#endif
